package virtualapp

import (
	"encoding/json"
	"fmt"
	"math"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/integerutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/jsonutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/stringutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/u64util"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/data/uuidutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/fileutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/function/reflectutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/model/dbinfo"
	"gitee.com/tomatomeatman/golang-repository/bricks2/model/msgentity"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/ginutil"
	"gitee.com/tomatomeatman/golang-repository/bricks2/utils/gorm"
	Log "github.com/cihub/seelog"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
)

var (
	recordKeyJam = "" //创建sRecordKey用的干扰串
	upFilePath   = "" //上传文件路径

	addRemoveNames       []string  //新增时需要排除的字段(不允许前端传入)
	addValidIgnoreNames  []string  //新增时检验的忽略字段
	editRemoveNames      []string  //修改时需要排除的字段(不允许前端传入)
	editValidIgnoreNames []string  //修改时检验的忽略字段
	addRemoveOnce        sync.Once //单次赋值操作
	addValidOnce         sync.Once //单次赋值操作
	editRemoveOnce       sync.Once //单次赋值操作
	editValidOnce        sync.Once //单次赋值操作
)

// 基类
type VirtualService struct {
	JsonDbName             string                `json:"jsonDbName"`             // 数据库名称别名,对应数据库全局配置名
	JsonName               string                `json:"jsonName"`               // 所在数据库表对象名(首字母小写)
	EnableTag              int                   `json:"enableTag"`              //控制操作值集合
	CheckRepeatCombination []string              `json:"checkRepeatCombination"` //检查待新增内容是否存在重复数据(多字段组合重复即重复)集合
	CheckRepeatAlone       map[string]int        `json:"checkRepeatAlone"`       //检查待新增内容是否存在重复数据(单独字段重复即重复)集合
	VirtualEntity          *dbinfo.VirtualEntity //对应的实体
}

/**
 * 创建服务对象
 * @param jsonDbName 数据库名称别名,对应数据库全局配置名
 * @param jsonName 数据库表对象名(首字母小写)
 * @return *VirtualService 返回服务对象
 */
func CreateService(jsonDbName, jsonName string) *VirtualService {
	// 读取json配置文件信息到实体中
	file, err := os.Open("./config/project/" + jsonDbName + "/service/" + jsonName + ".json")
	if err != nil {
		return nil
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	result := &VirtualService{}
	err = decoder.Decode(result)
	if err != nil {
		return nil
	}

	result.JsonDbName = jsonDbName
	result.JsonName = jsonName
	result.VirtualEntity = dbinfo.CreateVirtualEntity(jsonDbName, jsonName)

	if result.VirtualEntity != nil {
		result.VirtualEntity.EnableTag = result.EnableTag                           //控制操作值集合
		result.VirtualEntity.CheckRepeatCombination = result.CheckRepeatCombination //检查待新增内容是否存在重复数据(多字段组合重复即重复)集合
		result.VirtualEntity.CheckRepeatAlone = result.CheckRepeatAlone             //检查待新增内容是否存在重复数据(单独字段重复即重复)集合
	}

	return result
}

// ---------------- 业务层默认接口实现 ----------------//

/**
 * 验证新增数据是否存在重复 (一旦使用则覆盖通用方法)
 * @param ctx GinHttp上下文对象
 * @param refer 验证数据
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service *VirtualService) CheckRepeatByAdd(ctx ginutil.Context, refer *dbinfo.VirtualEntity) *msgentity.MsgEntity {
	return msgentity.Success(nil, "验证通过(默认验证通过)")
}

/**
 * 验证更新数据是否存在重复 (一旦使用则覆盖通用方法)
 * @param ctx GinHttp上下文对象
 * @param refer 待验证数据
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service *VirtualService) CheckRepeatByEdit(ctx ginutil.Context, refer *dbinfo.VirtualEntity) *msgentity.MsgEntity {
	return msgentity.Success(nil, "验证通过(默认验证通过)")
}

/**
 * 新增
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param data 数据
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) Add(ctx ginutil.Context, refer *dbinfo.VirtualEntity, data map[string]interface{}) *msgentity.MsgEntity {
	if refer.HasPid {
		return service.AddNode(ctx, refer, data)
	}

	return service.AddCommon(ctx, refer, data)
}

/**
 * 新增普通数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param data 数据
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) AddCommon(ctx ginutil.Context, refer *dbinfo.VirtualEntity, data map[string]interface{}) *msgentity.MsgEntity {
	stringutil.TrimAttribute(data) //清除对象各个属性的值的前后空格

	data = refer.RemoveData(data, addRemoveNameArray()...) //清理不能由前端定义的字段

	iCode, err := refer.ValidAttr(data, addValidIgnoreNameArray()...) //对对象中添加了dbinfo.DataInfo注解的不为nil的属性检查限制
	if err != nil {
		return msgentity.Err(iCode+7000, err)
	}

	commons := refer.Copy().FormMap(data)

	commons.SetDefault(false) //对对象中添加了fieldInfo注解的属性添加默认值

	me := service.SupplyDbEntityAttrByAdd(ctx, commons, "AAA", "") //补充除id外数据库实体类的数据--新增
	if !me.Success {
		return me.IncCode(7030)
	}

	iCode, err = commons.ValidAttrByAdd() //对对象中添加了dbinfo.DataInfo注解的属性检查限制
	if err != nil {
		return msgentity.Err(iCode+7020, err)
	}

	me = service.ValidEntityRepeatByAdd(ctx, commons) //验证新增数据是否存在重复
	if !me.Success {
		return me.IncCode(7031)
	}

	me = service.SupplyDbEntityAttrByAdd(ctx, commons, "", "") //补充数据库实体类的数据--新增
	if !me.Success {
		return me.IncCode(7032)
	}

	me = commonDao.AddCommon(commons)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 新增树节点
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param data 数据
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) AddNode(ctx ginutil.Context, refer *dbinfo.VirtualEntity, data map[string]interface{}) *msgentity.MsgEntity {
	stringutil.TrimAttribute(data) //清除对象各个属性的值的前后空格

	refer.RemoveData(data, addRemoveNameArray()...) //清理不能由前端定义的字段

	iCode, err := refer.ValidAttr(data, addValidIgnoreNameArray()...) //对对象中添加了dbinfo.DataInfo注解的不为nil的属性检查限制
	if err != nil {
		return msgentity.Err(iCode+7020, err)
	}

	commons := refer.Copy().FormMap(data)

	commons.SetDefault(false) //对对象中添加了fieldInfo注解的属性添加默认值

	me := service.SupplyDbEntityAttrByAdd(ctx, commons, "AAA", "") //补充除id外数据库实体类的数据--新增
	if !me.Success {
		return me.IncCode(7030)
	}

	iCode, err = commons.ValidAttrByAdd() //对对象中添加了dbinfo.DataInfo注解的属性检查限制
	if err != nil {
		return msgentity.Err(iCode+7020, err)
	}

	me = service.ValidEntityRepeatByAdd(ctx, commons) //验证新增数据是否存在重复
	if !me.Success {
		return me.IncCode(7031)
	}

	me = service.SupplyDbEntityAttrByAdd(ctx, commons, "", "") //补充除数据库实体类的数据--新增
	if !me.Success {
		return me.IncCode(7032)
	}

	me = commonDao.AddNode(commons)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 批量新增
 * @param ctx GinHttp上下文对象
 * @param refers 检查用数据结构
 * @param 请求参数
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) AddsVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	var list []map[string]interface{}
	if v, ok := params["list"]; ok {
		list = v.([]map[string]interface{})
	}

	if len(list) < 1 {
		return msgentity.Err(9102, "没有需要保存的数据")
	}

	return service.Adds(ctx, refer, list)
}

/**
 * 批量新增
 * @param ctx GinHttp上下文对象
 * @param refers 检查用数据结构
 * @param list数据
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) Adds(ctx ginutil.Context, refer *dbinfo.VirtualEntity, list []map[string]interface{}) *msgentity.MsgEntity {
	if len(list) < 1 {
		return msgentity.Err(8001, "没有需要保存的数据")
	}

	entitysNew := []*dbinfo.VirtualEntity{}
	for _, vData := range list {
		stringutil.TrimAttribute(vData) //清除对象各个属性的值的前后空格

		vData = refer.RemoveData(vData, addRemoveNameArray()...) //清理不能由前端定义的字段

		iCode, err := refer.ValidAttr(vData, addValidIgnoreNameArray()...) //对对象中添加了dbinfo.DataInfo注解的不为nil的属性检查限制
		if err != nil {
			return msgentity.Err(iCode+7000, err)
		}

		commons := refer.Copy().FormMap(vData)

		commons.SetDefault(false) //对对象中添加了fieldInfo注解的属性添加默认值

		me := service.SupplyDbEntityAttrByAdd(ctx, commons, "AAA", "") //补充除id外数据库实体类的数据--新增
		if !me.Success {
			return me.IncCode(7030)
		}

		iCode, err = commons.ValidAttrByAdd() //对对象中添加了dbinfo.DataInfo注解的属性检查限制
		if err != nil {
			return msgentity.Err(iCode+7020, err)
		}

		me = service.ValidEntityRepeatByAdd(ctx, commons) //验证新增数据是否存在重复
		if !me.Success {
			return me.IncCode(7030)
		}

		me = service.SupplyDbEntityAttrByAdd(ctx, commons, "", "") //补充数据库实体类的数据--新增
		if !me.Success {
			return me.IncCode(7030)
		}

		entitysNew = append(entitysNew, commons)
	}

	me := commonDao.Adds(entitysNew)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 批量新增
 * @param ctx GinHttp上下文对象
 * @param datas 检查用数据结构
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) AddListVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	var list []map[string]interface{}
	if v, ok := params["datas"]; ok {
		list = v.([]map[string]interface{})
	}

	if len(list) < 1 {
		return msgentity.Err(9102, "没有需要保存的数据")
	}

	datas := []*dbinfo.VirtualEntity{}
	for _, obj := range list {
		temp := refer.Copy().FormMap(obj)
		datas = append(datas, temp)
	}

	return service.AddList(ctx, datas)
}

/**
 * 批量新增
 * @param ctx GinHttp上下文对象
 * @param datas 检查用数据结构
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) AddList(ctx ginutil.Context, datas []*dbinfo.VirtualEntity) *msgentity.MsgEntity {
	if len(datas) < 1 {
		return msgentity.Err(8001, "没有需要保存的数据")
	}

	for _, refer := range datas {
		refer.SetDefault(false) //对对象中添加了fieldInfo注解的属性添加默认值
		me := service.SupplyDbEntityAttrByAdd(ctx, refer, "", "")
		if !me.Success {
			return me.IncCode(7030)
		}
	}

	me := commonDao.Adds(datas)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + datas[0].TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 修改状态
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param id 编号
 * @param state 状态值
 * @param edition 记录版本号
 * @param memo 备注
 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
 * @return *msgentity.MsgEntity 返回验证结果 返回执行情况
 */
func (service VirtualService) ChangeStateVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	id := params[refer.KeyJson]

	state := -1
	if v, ok := params[dbinfo.TableState[1]]; ok {
		state = v.(int)
	}

	edition := -1
	if v, ok := params[dbinfo.TableEdition[1]]; ok {
		edition = v.(int)
	}

	memo := ""
	if v, ok := params[dbinfo.TableMemo[1]]; ok {
		memo = v.(string)
	}

	unidirectional := integerutil.ToInt(params["unidirectional"], 0) == 1

	return commonDao.ChangeState(refer, id, state, edition, memo, unidirectional)
}

/**
 * 修改状态
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param id 编号
 * @param state 状态值
 * @param edition 记录版本号
 * @param memo 备注
 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
 * @return *msgentity.MsgEntity 返回验证结果 返回执行情况
 */
func (service VirtualService) ChangeState(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, state int, edition int, memo string, unidirectional bool) *msgentity.MsgEntity {
	if fmt.Sprintf("%v", id) == "" {
		return msgentity.Err(8001, "记录编号参数为空！")
	}

	return commonDao.ChangeState(refer, id, state, edition, memo, unidirectional)
}

/**
 * 修改步骤值(如果设置为单向则新值必须大于旧值)
 * @param ctx GinHttp上下文对象
 * @param id 编号
 * @param setp 步骤值
 * @param edition 记录版本号
 * @param memo 备注
 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
 * @param refer 实体类
 * @return *msgentity.MsgEntity 返回验证结果 返回执行情况
 */
func (service VirtualService) ChangeSetpVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	id := params[refer.KeyJson]

	setp := -1
	if v, ok := params[dbinfo.TableSetp[1]]; ok {
		setp = v.(int)
	}

	edition := -1
	if v, ok := params[dbinfo.TableEdition[1]]; ok {
		edition = v.(int)
	}

	memo := ""
	if v, ok := params[dbinfo.TableMemo[1]]; ok {
		memo = v.(string)
	}

	unidirectional := integerutil.ToInt(params["unidirectional"], 0) == 1

	return service.ChangeSetp(ctx, refer, id, setp, edition, memo, unidirectional)
}

/**
 * 修改步骤值(如果设置为单向则新值必须大于旧值)
 * @param ctx GinHttp上下文对象
 * @param id 编号
 * @param setp 步骤值
 * @param edition 记录版本号
 * @param memo 备注
 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
 * @param refer 实体类
 * @return *msgentity.MsgEntity 返回验证结果 返回执行情况
 */
func (service VirtualService) ChangeSetp(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, setp int, edition int, memo string, unidirectional bool) *msgentity.MsgEntity {
	if fmt.Sprintf("%v", id) == "" {
		return msgentity.Err(8001, "记录编号参数为空！")
	}

	return commonDao.ChangeSetp(refer, id, setp, edition, memo, unidirectional)
}

/**
 * 删除
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param id 记录编号值
 * @param edition 记录版本号
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) DelVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	id := params[refer.KeyJson]

	edition := -1
	if v, ok := params[dbinfo.TableEdition[1]]; ok {
		edition = v.(int)
	}

	if id != nil {
		return service.Del(ctx, refer, id, edition)
	}

	var whereInfo []dbinfo.WhereInfo
	if v, ok := params["whereInfo"]; ok {
		whereInfo = v.([]dbinfo.WhereInfo)
	}

	if len(whereInfo) > 0 {
		return service.DelByMap(ctx, refer, whereInfo)
	}

	return msgentity.Err(9102, "请求参数未明确")
}

/**
 * 删除
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param id 记录编号值
 * @param edition 记录版本号
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) Del(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, edition int) *msgentity.MsgEntity {
	if id == nil {
		return msgentity.Err(8001, "记录编号为空")
	}

	if refer.HasEdition && (edition < 1) && (edition != integerutil.MaxInt()) {
		return msgentity.Err(8002, "记录版本号不正确")
	}

	onlyCreator := !EnableTag(refer, 7) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	physics := !EnableTag(refer, 1)   //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
	if !physics && refer.HasDelSign { //有逻辑删除字段标识才能进行逻辑删除
		return commonDao.DelSign(refer, id, edition, CurrentLoginUserId(ctx.Request), onlyCreator) //标识删除
	}

	me := commonDao.Del(refer, id, edition, CurrentLoginUserId(ctx.Request), onlyCreator)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 根据条件删除
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param where 执行条件
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) DelByMap(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo) *msgentity.MsgEntity {
	if refer == nil {
		return msgentity.Err(8001, "结构体参数为nil")
	}
	onlyCreator := !EnableTag(refer, 7) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	physics := !EnableTag(refer, 1)   //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
	if !physics && refer.HasDelSign { //有逻辑删除字段标识才能进行逻辑删除
		return commonDao.DelSignByMap(refer, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator) //标识删除
	}

	me := commonDao.DelByMap(refer, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 按实体保留map中的数据
 * @param refer 对象类型
 * @param data 数据
 * @return map[string]interface{} 返回保留后的数据
 */
func (service VirtualService) HoldByEntity(refer *dbinfo.VirtualEntity, data map[string]interface{}) map[string]interface{} {
	result := map[string]interface{}{}
	for key, value := range data {
		if _, ok := refer.Fields[key]; !ok {
			continue
		}

		result[key] = value
	}

	return result
}

/**
 * 修改
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param data 待更新的字段和值
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) Edit(ctx ginutil.Context, refer *dbinfo.VirtualEntity, data map[string]interface{}) *msgentity.MsgEntity {
	id, ok := data[refer.KeyJson] //记录编号值
	if !ok || id == "" {
		return service.Add(ctx, refer, data)
	}

	edition := -1 //记录版本号
	if temp, ok := data[dbinfo.TableEdition[1]]; ok {
		edition = temp.(int)
	}

	if fmt.Sprintf("%v", id) == "" {
		return msgentity.Err(7001, "记录编号参数为空！")
	}

	data = refer.HoldByEntity(data)                         //按实体保留map中的数据
	data = refer.RemoveData(data, editRemoveNameArray()...) //清理不能由前端定义的字段

	if len(data) < 1 {
		return msgentity.Err(7002, "更新操作提供的参数为空！")
	}

	if refer.HasEdition && (1 > edition) {
		return msgentity.Err(7003, "记录版本号参数必须大于0！")
	}

	var oldData map[string]interface{}
	if refer.HasRecordKey { //如果存在RecordKey标识，则必须进行记录校验
		me := commonDao.FindById(refer, id, "", false)
		if me == nil {
			return msgentity.Err(7004, "记录不存在！")
		}

		oldData = me.Data.(map[string]interface{})
		nowKey := refer.CreateRecordKeyByMap(oldData)

		if nowKey != oldData["RecordKey"] {
			return msgentity.Err(7005, "记录校验失败！")
		}
	}

	stringutil.TrimAttribute(data) //清除对象各个属性的值的前后空格

	iCode, err := refer.ValidAttr(data, editValidIgnoreNameArray()...) //对对象中添加了dbinfo.DataInfo注解的不为nil的属性检查限制
	if err != nil {
		return msgentity.Err(iCode + 7020)
	}

	me := service.ValidEntityRepeatByEdit(ctx, refer, id, data) //验证更新数据是否存在重复
	if !me.Success {
		return me.IncCode(7030)
	}

	//进行前端不可传递数据处理,如:修改者、修改时间等信息清理并赋值
	service.SupplyDbEntityAttrByEdit(ctx, data, refer)

	if refer.HasRecordKey { //如果存在RecordKey标识，则必须重新对数据的检验字段进行生成
		for key, val := range data { //覆盖旧数据:警告oldData后面不能再用
			oldData[key] = val
		}

		data[dbinfo.TableRecordKey[1]] = refer.CreateRecordKeyByMap(oldData) //更新RecordKey
	}

	onlyCreator := !EnableTag(refer, 6) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	me = commonDao.Edit(refer, id, edition, data, CurrentLoginUserId(ctx.Request), onlyCreator)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 批量修改
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param datas 待更新的字段和值集合
 * @param transactional 启用事务
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) EditsVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	var datas []map[string]interface{}
	if v, ok := params["datas"]; ok {
		datas = v.([]map[string]interface{})
	}

	transactional := integerutil.ToInt(params["transactional"], 0) == 1

	return service.Edits(ctx, service.VirtualEntity, datas, transactional)
}

/**
 * 批量修改
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param datas 待更新的字段和值集合
 * @param transactional 启用事务
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) Edits(ctx ginutil.Context, refer *dbinfo.VirtualEntity, datas []map[string]interface{}, transactional bool) *msgentity.MsgEntity {
	if len(datas) < 1 {
		return msgentity.Err(7001, "待更新集合参数为空！")
	}

	onlyCreator := !EnableTag(refer, 6) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	saveDatas := []map[string]interface{}{}
	for _, data := range datas {
		id := data[refer.KeyJson]
		edition := -1

		temp, ok := data[dbinfo.TableEdition[1]]
		if ok {
			edition = temp.(int)
		}

		data = refer.HoldByEntity(data) //按实体保留map中的数据
		// maputil.RemoveData(data, []string{"uId", "id", "iId", "sPath", "sCreator", "sModifieder", "dCreateDate", "dModifiedDate", "edition",
		// 	"u_id", "s_id", "i_id", "s_path", "s_creator", "s_modifieder", "d_create_date", "d_modified_date", "i_edition"}) //清理不能由前端定义的字段
		data = refer.RemoveData(data, editRemoveNameArray()...) //清理不能由前端定义的字段

		if len(data) < 1 {
			return msgentity.Err(7002, "更新操作提供的参数为空！")
		}

		if refer.HasEdition && (1 > edition) {
			return msgentity.Err(7003, "记录版本号参数必须大于0！")
		}

		var oldData map[string]interface{}
		if refer.HasRecordKey { //如果存在RecordKey标识，则必须进行记录校验
			me := commonDao.FindById(refer, id, "", false)
			if me == nil {
				return msgentity.Err(7004, "记录不存在！")
			}

			oldData = me.Data.(map[string]interface{})
			nowKey := refer.CreateRecordKeyByMap(oldData)

			if nowKey != oldData["RecordKey"] {
				return msgentity.Err(7005, "记录校验失败！")
			}
		}

		stringutil.TrimAttribute(data) //清除对象各个属性的值的前后空格

		iCode, err := refer.ValidAttr(data, editValidIgnoreNameArray()...) //对对象中添加了dbinfo.DataInfo注解的不为nil的属性检查限制
		if err != nil {
			return msgentity.Err(iCode + 7020)
		}

		me := service.ValidEntityRepeatByEdit(ctx, refer, id, data) //验证更新数据是否存在重复
		if !me.Success {
			return me.IncCode(7030)
		}

		//进行前端不可传递数据处理,如:修改者、修改时间等信息清理并赋值
		service.SupplyDbEntityAttrByEdit(ctx, data, refer)

		if refer.HasRecordKey { //如果存在RecordKey标识，则必须重新对数据的检验字段进行生成
			for key, val := range data { //覆盖旧数据:警告oldData后面不能再用
				oldData[key] = val
			}

			data[dbinfo.TableRecordKey[1]] = refer.CreateRecordKeyByMap(oldData) //更新RecordKey
		}

		saveDatas = append(saveDatas, data)

	}

	if transactional {
		return commonDao.Edits(refer, saveDatas, CurrentLoginUserId(ctx.Request), onlyCreator)
	}

	result := 0

	for _, data := range saveDatas {
		id := data[refer.KeyJson]
		edition := -1

		temp, ok := data[dbinfo.TableEdition[1]]
		if ok {
			edition = temp.(int)
		}

		me := commonDao.Edit(refer, id, edition, data, CurrentLoginUserId(ctx.Request), onlyCreator)
		if me.Success {
			result++
		}
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return msgentity.Success(result, "请求结束")
}

/**
 * 保存(有ID则更新,否则新增)
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param data 待保存数据
 * @return msgentity.MsgEntity
 */
func (service VirtualService) Save(ctx ginutil.Context, refer *dbinfo.VirtualEntity, data map[string]interface{}) *msgentity.MsgEntity {
	if len(data) < 1 {
		return msgentity.Err(7001, "待保存数据为空！")
	}

	id, ok := data[refer.KeyJson]
	if !ok || id == "" {
		return service.Add(ctx, refer, data)
	}

	me := service.Edit(ctx, refer, data)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 批量保存
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param datas 待保存集合
 * @param transactional 是否启用事务
 * @return msgentity.MsgEntity
 */
func (service VirtualService) SavesVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	var datas []map[string]interface{}
	if v, ok := params["datas"]; ok {
		datas = v.([]map[string]interface{})
	}

	transactional := integerutil.ToInt(params["transactional"], 0) == 1

	return service.Saves(ctx, refer, datas, transactional)
}

/**
 * 批量保存
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param datas 待保存集合
 * @param transactional 是否启用事务
 * @return msgentity.MsgEntity
 */
func (service VirtualService) Saves(ctx ginutil.Context, refer *dbinfo.VirtualEntity, datas []map[string]interface{}, transactional bool) *msgentity.MsgEntity {
	if len(datas) < 1 {
		return msgentity.Err(7001, "待保存集合参数为空！")
	}

	addList := []map[string]interface{}{}
	editList := []map[string]interface{}{}
	delList := []map[string]interface{}{}

	for _, data := range datas {
		id, ok := data[refer.KeyJson]
		if !ok || id == "" {
			addList = append(addList, data)
		} else {
			editList = append(editList, data)
		}
	}

	me := service.SaveList(ctx, refer, addList, editList, delList, transactional)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 批量操作
 * @param ctx GinHttp上下文对象
 * @param refer 对象类型
 * @param addList 待新增集合
 * @param editList 待更新集合
 * @param delList 待删除集合
 * @param transactional 是否启用事务
 * @return msgentity.MsgEntity
 */
func (service VirtualService) SaveList(ctx ginutil.Context, refer *dbinfo.VirtualEntity, addList, editList, delList []map[string]interface{}, transactional bool) *msgentity.MsgEntity {
	onlyCreator := !EnableTag(refer, 6) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
	currentUser := CurrentLoginUserId(ctx.Request)
	me := commonDao.SaveList(refer, addList, editList, delList, currentUser, onlyCreator, transactional)
	if !me.Success {
		return me
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.TableName
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return me
}

/**
 * 根据主键查询数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param id 主键
 */
func (service VirtualService) FindById(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}) *msgentity.MsgEntity {
	if id == nil {
		return msgentity.Err(1001, "记录编号为空")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindById(refer, id, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 查询所有数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param whereInfo 查询条件
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindAllVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	var whereInfo []dbinfo.WhereInfo
	if v, ok := params["whereInfo"]; ok {
		whereInfo = v.([]dbinfo.WhereInfo)
	}

	return service.FindAll(ctx, service.VirtualEntity, whereInfo)
}

/**
 * 查询所有数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param whereInfo 查询条件
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindAll(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo) *msgentity.MsgEntity {
	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindAll(refer, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 查询指定时间内数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param id 主键
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindByDate(ctx ginutil.Context, refer *dbinfo.VirtualEntity, dateSt string, dateEd string) *msgentity.MsgEntity {
	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindByDate(refer, dateSt, dateEd, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 查询指定行数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param id 主键
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindByRow(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}) *msgentity.MsgEntity {
	if id == nil {
		return msgentity.Err(1001, "记录编号为空")
	}

	Id := fmt.Sprintf("%v", id)
	if Id == "" {
		return msgentity.Err(1002, "记录编号为空")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindByRow(refer, id, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 查询分页数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param findByPageParam 查询分页参数
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindByPage(ctx ginutil.Context, refer *dbinfo.VirtualEntity, findByPageParam dbinfo.FindByPageParam) *msgentity.MsgEntity {
	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindByPage(refer, findByPageParam, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 补充数据库实体类的数据--新增
 * @param ctx GinHttp上下文对象
 * @param refer
 * @param selfId 自提供的编号,防止从序列中获取
 * @param idValuePrefix Id前缀
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) SupplyDbEntityAttrByAdd(ctx ginutil.Context, refer *dbinfo.VirtualEntity, selfId string, idValuePrefix string) *msgentity.MsgEntity {
	if refer == nil {
		return msgentity.Err(1001, "待存储的数据实体不能为nil")
	}

	refer.SetDefault(false) //对对象中添加了fieldInfo注解的属性添加默认值

	LoginUserId := CurrentLoginUserId(ctx.Request) //取当前登录用户编号
	date := time.Now()

	refer.SetValue(dbinfo.TableCreator[1], LoginUserId)    // 设置当前操作用户
	refer.SetValue(dbinfo.TableModifieder[1], LoginUserId) // 设置当前操作用户
	refer.SetValue(dbinfo.TableCreateDate[1], date)        // 设置新增时间
	refer.SetValue(dbinfo.TableModifiedDate[1], date)      // 设置修改时间
	refer.SetValue(dbinfo.TableRrank[1], 1)                // 设置排序值
	refer.SetValue(dbinfo.TableState[1], 1)                // 设置状态值
	refer.SetValue(dbinfo.TableEdition[1], 1)              // 设置版本号

	//--如果有Pid字段则进行部分处理--//
	if refer.HasPid {
		pid := refer.GetValue(dbinfo.TablePidKey[1])
		if (pid == nil) || (pid.(string) == "") { //如果Pid为空,则默认赋值'00'
			refer.SetValue(dbinfo.TablePidKey[1], dbinfo.TableTreeRootValue)
		}
	}

	//-- 设置id --//
	newId := ""

	if selfId != "" && !refer.AutoKey { //有自定义id值
		idName := refer.KeyJson
		refer.SetValue(idName, strings.ToUpper(selfId))
	} else if (selfId == "") && !refer.AutoKey { //如果不是自增长,并且没有自定义id值,才能进行从序列中取新id的方法
		if refer.HasPath { //对象中存在Path,则id需要按节点生成
			pid := refer.GetValue(dbinfo.TablePidKey[1]) //前面已经设置pid值

			me := commonDao.NewChildId(refer, pid.(string))
			if !me.Success {
				return me
			}

			newId = me.Data.(string)
			refer.SetValue(dbinfo.TableMajorKeyString[1], newId)
		} else if refer.KeyLen == 32 { //按32位UUID设置值
			newId = strings.Replace(uuid.NewV4().String(), "-", "", -1) //取uuid
			refer.SetValue(dbinfo.TableMajorKeyUuId[1], strings.ToUpper(newId))
		} else if refer.KeyLen == 22 { //按22位UUID设置值
			refer.SetValue(dbinfo.TableMajorKeyUuId[1], u64util.Get(idValuePrefix))
		} else if idValuePrefix == "" {
			newId = GetNewId(refer.KeyLen, refer.TableName)
			refer.SetValue(dbinfo.TableMajorKeyString[1], newId)
		} else {
			iLength := refer.KeyLen - len(idValuePrefix)
			newId = idValuePrefix + GetNewId(iLength, refer.TableName)
			refer.SetValue(dbinfo.TableMajorKeyString[1], newId)
		}
	}

	//--如果有path字段则进行部分处理--//
	if (newId != "") && refer.HasPath {
		path := idToPath(newId)
		refer.SetValue(dbinfo.TablePathKey[1], path)

		pid := refer.GetValue(dbinfo.TablePidKey[1])
		if (pid == nil) || (pid.(string) == "") { //如果pid为空,则默认赋值'00'
			refer.SetValue(dbinfo.TablePidKey[1], dbinfo.TableTreeRootValue[0])
		}
	}

	//--如果有recordKey字段则进行部分处理--//
	if refer.HasRecordKey {
		if recordKeyJam == "" {
			recordKeyJam = ReadConfigKey("App", "RecordKeyJam", "12345678").(string)
		}

		key := reflectutil.DoMethod(refer, "CreateRecordKey", reflect.ValueOf(recordKeyJam))
		if len(key) > 0 {
			refer.SetValue(dbinfo.TableRecordKey[1], key[0])
		}
	}

	return msgentity.Success(1999, "补充数据完毕！")
}

/**
 * 补充数据库实体类的数据--修改
 * @param ctx GinHttp上下文对象
 * @param data 待修改的数据
 * @param refer 参照结构体
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) SupplyDbEntityAttrByEdit(ctx ginutil.Context, data map[string]interface{}, refer *dbinfo.VirtualEntity) *msgentity.MsgEntity {
	if len(data) < 1 {
		return msgentity.Err(1001, "待修改的数据不能为nil")
	}

	LoginUserId := CurrentLoginUserId(ctx.Request) //取当前登录用户编号

	if refer.HasCreator {
		delete(data, dbinfo.TableCreator[1]) // 清理,限制不允许修改创建人
	}

	if refer.HasCreateDate {
		delete(data, dbinfo.TableCreateDate[1]) // 清理,限制不允许修改设置新增时间
	}

	if refer.HasDelSign {
		delete(data, dbinfo.TableDelSign[1]) // 清理,限制不允许修改删除标识
	}

	if refer.HasModifieder {
		data[dbinfo.TableModifieder[1]] = LoginUserId // 设置当前操作用户
	}

	if refer.HasModifiedDate {
		data[dbinfo.TableModifiedDate[1]] = time.Now() // 设置修改时间
	}

	if refer.HasEdition {
		data[dbinfo.TableEdition[1]] = data[dbinfo.TableEdition[1]].(int) + 1 // 设置版本号
	}

	//--如果有sRecordKey字段则进行部分处理,为提高效率,在edit中处理--//

	return msgentity.Success(1999, "补充数据完毕！")
}

/**
 * 验证新增数据是否存在重复
 * @param ctx GinHttp上下文对象
 * @param entity 参照结构体
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) ValidEntityRepeatByAdd(ctx ginutil.Context, entity *dbinfo.VirtualEntity) *msgentity.MsgEntity {
	//-- 树形结构 --//
	if entity.HasPid {
		return service.CommonCheckRepeatByAddAndTree(ctx, entity) //通用树型结构表添加数据时重复检查方法
	}

	//--不是树形数据则使用普通方法检查--//
	return service.CommonCheckRepeatByAdd(ctx, entity) //通用添加数据时重复检查方法
}

/**
 * 验证更新数据是否存在重复
 * @param ctx GinHttp上下文对象
 * @param refer 参照结构体
 * @param id 主键值
 * @param data 待修改的数据
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) ValidEntityRepeatByEdit(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, data map[string]interface{}) *msgentity.MsgEntity {
	//-- 树形结构 --//
	if refer.HasPid {
		return service.CommonCheckRepeatByEditAndTree(ctx, refer, id, data["Name"]) //通用树型结构表添加数据时重复检查方法
	}

	//--不是树形数据则使用普通方法检查--//
	return service.CommonCheckRepeatByEdit(ctx, refer, id, data) //通用添加数据时重复检查方法
}

/**
 * 通用树型结构表添加数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param entity
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) CommonCheckRepeatByAddAndTree(ctx ginutil.Context, entity *dbinfo.VirtualEntity) *msgentity.MsgEntity {
	vName := entity.GetValue(dbinfo.TableTreeNode[1])
	if vName == nil {
		return msgentity.Err(1001, "节点名称为空")
	}

	name := vName.(string)

	var pid string
	vPid := entity.GetValue(dbinfo.TablePidKey[1])
	if vPid != nil {
		pid = vPid.(string)
	} else {
		pid = dbinfo.TableTreeRootValue[1]
	}

	if pid == "" {
		pid = dbinfo.TableTreeRootValue[1]
	}

	where := make(map[string]interface{})

	//同一层节点下,展现名不能相同//
	var build strings.Builder
	build.WriteString("SELECT SUM(iCount) AS iCount FROM (")

	if entity.HasSign {
		build.WriteString(" 	select SIGN(COUNT(1) * 10) as iCount from ${DbTableName}")
		build.WriteString(" 	where ")
		build.WriteString(dbinfo.TableSign[0])
		build.WriteString(" =@")
		build.WriteString(dbinfo.TableSign[1])
		build.WriteString(" UNION ALL ")

		where[dbinfo.TableSign[1]] = entity.GetValue(dbinfo.TableSign[1])
	}

	build.WriteString(" 	select SIGN(COUNT(1)) as iCount from ${DbTableName}")
	build.WriteString(" 	where ${PidKey} = @Pid and ${TreeNodeName} = @Name")
	build.WriteString(") TMP")

	txt := build.String()
	txt = strings.Replace(txt, "${DbTableName}", gorm.GetDbName(entity.JsonDbName)+entity.TableName, -1)
	txt = strings.Replace(txt, "${TableName}", entity.TableName, -1)
	txt = strings.Replace(txt, "${PidKey}", dbinfo.TablePidKey[0], -1)
	txt = strings.Replace(txt, "${TreeNodeName}", dbinfo.TableTreeNode[0], -1)

	where["Pid"] = pid
	where["Name"] = name

	var iCount int
	dbResult := gorm.Raw(txt, where).Find(&iCount)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return msgentity.Err(1002, "查询数据发生异常:", dbResult.Error)
	}

	if iCount != 0 {
		return msgentity.Err(1003, "节点重复")
	}

	return msgentity.Success(1999, "节点未重复")
}

/**
 * 通用树型结构表添加数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param refer
 * @param id
 * @param name
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) CommonCheckRepeatByEditAndTree(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, name interface{}) *msgentity.MsgEntity {
	if (name == nil) || (name == "") || (name == "<nil>") {
		return msgentity.Err(1001, "节点名称为空")
	}

	where := make(map[string]interface{})

	//同一层节点下,展现名不能相同//
	var build strings.Builder
	build.WriteString("SELECT SUM(iCount) AS iCount FROM (")

	if refer.HasSign {
		build.WriteString(" 	select SIGN(COUNT(1) * 10) as iCount from ${DbTableName}")
		build.WriteString(" 	where ")
		build.WriteString(dbinfo.TableSign[0])
		build.WriteString(" =@")
		build.WriteString(dbinfo.TableSign[1])
		build.WriteString(" 	and ${Id} <> @Id")
		build.WriteString(" UNION ALL ")

		where[dbinfo.TableSign[1]] = refer.GetValue(dbinfo.TableSign[1])
	}

	build.WriteString(" 	select SIGN(COUNT(1)) as iCount from ${DbTableName}")
	build.WriteString(" 	where ${Id} <> @Id")
	build.WriteString(" 	and ${PidKey} = (select a.${PidKey} from ${DbTableName} a where a.${Id} =@Id)")
	build.WriteString(" 	and ${TreeNodeName} =@Name")
	build.WriteString(") TMP")

	txt := build.String()
	txt = strings.Replace(txt, "${DbTableName}", gorm.GetDbName(refer.JsonDbName)+refer.TableName, -1)
	txt = strings.Replace(txt, "${TableName}", refer.TableName, -1)
	txt = strings.Replace(txt, "${Id}", refer.KeyField, -1)
	txt = strings.Replace(txt, "${PidKey}", dbinfo.TablePidKey[0], -1)
	txt = strings.Replace(txt, "${TreeNodeName}", dbinfo.TableTreeNode[0], -1)

	where["Id"] = id
	where["Name"] = name

	var iCount int
	dbResult := gorm.Raw(txt, where).Find(&iCount)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return msgentity.Err(1002, "查询数据发生异常:", dbResult.Error)
	}

	if iCount != 0 {
		return msgentity.Err(1003, "节点重复")
	}

	return msgentity.Success(1999, "节点未重复")
}

/**
 * 通用添加数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param entity
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) CommonCheckRepeatByAdd(ctx ginutil.Context, entity *dbinfo.VirtualEntity) *msgentity.MsgEntity {
	vCheckRepeatCombination := entity.CheckRepeatCombination
	vCheckRepeatAlone := entity.CheckRepeatAlone

	k := 0

	//检查待新增内容是否存在重复数据(多字段组合重复即重复)集合
	if (vCheckRepeatCombination != nil) && (len(vCheckRepeatCombination) > 0) {
		checkRepeatCombination := vCheckRepeatCombination

		var build strings.Builder
		build.WriteString("SELECT COUNT(1) AS iCount FROM ${DbTableName} WHERE 1=1")

		var temp strings.Builder
		temp.WriteString("[")

		where := make(map[string]interface{})
		for _, value := range checkRepeatCombination {
			fieldInfo := entity.GetField(value)
			build.WriteString(" AND ")
			build.WriteString(fieldInfo.Field)
			build.WriteString(" =@")
			build.WriteString(value)

			where[value] = reflectutil.GetFieldValue(entity, value)

			temp.WriteString("、'")
			temp.WriteString(fieldInfo.Comment)
			temp.WriteString("'")
		}

		txt := strings.Replace(build.String(), "1=1 AND ", "", -1)
		txt = strings.Replace(txt, "${DbTableName}", gorm.GetDbName(entity.JsonDbName)+entity.TableName, -1)
		txt = strings.Replace(txt, "${TableName}", entity.TableName, -1)

		iCount := 0
		dbResult := gorm.Raw(txt, where).Find(&iCount)
		if dbResult.Error != nil {
			Log.Error("验证数据是否重复发生异常:", dbResult.Error)
			return msgentity.Err(1001, "验证数据是否重复发生异常:", dbResult.Error)
		}

		if iCount != 0 {
			temp.WriteString("]组合发现数据重复")
			return msgentity.Err(1002, strings.Replace(temp.String(), "、", "", 1))
		}

		k++
	}

	//检查待新增内容是否存在重复数据(单独字段重复即重复)集合
	if (vCheckRepeatAlone != nil) && (len(vCheckRepeatAlone) > 0) {
		checkRepeatAlone := vCheckRepeatAlone

		var build strings.Builder
		build.WriteString("SELECT SUM(iCount) FROM (")

		where := make(map[string]interface{})
		for key, value := range checkRepeatAlone {
			fieldInfo := entity.GetField(key)
			build.WriteString(" union all select (SIGN(COUNT(1)) * ")
			build.WriteString(strconv.Itoa(value))
			build.WriteString(") as iCount ")
			build.WriteString(" from ${DbTableName} ")
			build.WriteString(" where ")
			build.WriteString(fieldInfo.Field)
			build.WriteString("= @")
			build.WriteString(key)

			where[key] = reflectutil.GetFieldValue(entity, key)
		}

		build.WriteString(") TMP")

		txt := strings.Replace(build.String(), " union all ", " ", 1)
		txt = strings.Replace(txt, "${DbTableName}", gorm.GetDbName(entity.JsonDbName)+entity.TableName, -1)
		txt = strings.Replace(txt, "${TableName}", entity.TableName, -1)

		iCount := 0
		dbResult := gorm.Raw(txt, where).Find(&iCount)
		if dbResult.Error != nil {
			Log.Error("验证数据是否重复发生异常:", dbResult.Error)
			return msgentity.Err(1003, "验证数据是否重复发生异常:", dbResult.Error)
		}

		if iCount != 0 {
			var temp strings.Builder
			str := fmt.Sprintf("%0*d", len(checkRepeatAlone), iCount)
			array := []rune(str) //得到字符数组

			ml := len(checkRepeatAlone)
			for key, value := range checkRepeatAlone {
				i := len(strconv.Itoa(value))
				if array[ml-i] == 48 { // ASCII对应: '0' => 48, '1' => 49
					continue
				}

				fieldInfo := entity.GetField(key)
				temp.WriteString("、'")
				temp.WriteString(fieldInfo.Comment)
				temp.WriteString("'")
			}

			temp.WriteString("存在重复")

			return msgentity.Err(1004, strings.Replace(temp.String(), "、", "", 1))
		}

		k++
	}

	if k == 0 {
		return msgentity.Success("没有设定验证函数,通过")
	}

	return msgentity.Success("经验证,通过")
}

/**
 * 通用更新数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param refer
 * @param id
 * @param data
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) CommonCheckRepeatByEdit(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, data map[string]interface{}) *msgentity.MsgEntity {
	vCheckRepeatCombination := refer.CheckRepeatCombination
	vCheckRepeatAlone := refer.CheckRepeatAlone

	k := 0

	//检查待修改内容是否存在重复数据(多字段组合重复即重复)集合
	if (vCheckRepeatCombination != nil) && (len(vCheckRepeatCombination) > 0) {
		checkRepeatCombination := vCheckRepeatCombination

		var build strings.Builder
		build.WriteString("SELECT COUNT(1) AS iCount FROM ${DbTableName} WHERE 1=1")

		var temp strings.Builder
		temp.WriteString("[")

		where := make(map[string]interface{})
		where[refer.KeyJson] = id
		build.WriteString(" AND ")
		build.WriteString(refer.KeyField)
		build.WriteString(" != @")
		build.WriteString(refer.KeyJson)

		for _, value := range checkRepeatCombination {
			fieldInfo := refer.GetField(value)
			build.WriteString(" AND ")
			build.WriteString(fieldInfo.Field)
			build.WriteString(" =@")
			build.WriteString(value)

			where[value] = data[value] // reflectutil.GetFieldValue(refer, "G"+value)

			temp.WriteString("、'")
			temp.WriteString(fieldInfo.Comment)
			temp.WriteString("'")
		}

		txt := strings.Replace(build.String(), "1=1 AND ", "", -1)
		txt = strings.Replace(txt, "${DbTableName}", gorm.GetDbName(refer.JsonDbName)+refer.TableName, -1)
		txt = strings.Replace(txt, "${TableName}", refer.TableName, -1)

		iCount := 0
		dbResult := gorm.Raw(txt, where).Find(&iCount)
		if dbResult.Error != nil {
			Log.Error("验证数据是否重复发生异常:", dbResult.Error)
			return msgentity.Err(1001, "验证数据是否重复发生异常:", dbResult.Error)
		}

		if iCount != 0 {
			temp.WriteString("]组合发现数据重复")
			return msgentity.Err(1002, strings.Replace(temp.String(), "、", "", 1))
		}

		k++
	}

	//检查待修改内容是否存在重复数据(单独字段重复即重复)集合
	if (vCheckRepeatAlone != nil) && (len(vCheckRepeatAlone) > 0) {
		checkRepeatAlone := vCheckRepeatAlone

		var build strings.Builder
		build.WriteString("SELECT SUM(iCount) FROM (")

		where := make(map[string]interface{})
		where[refer.KeyJson] = id

		for key, value := range checkRepeatAlone {
			fieldInfo := refer.GetField(key)
			build.WriteString(" union all select (SIGN(COUNT(1)) * ")
			build.WriteString(strconv.Itoa(value))
			build.WriteString(") as iCount ")
			build.WriteString(" from ${DbTableName} ")
			build.WriteString(" where ")
			build.WriteString(fieldInfo.Field)
			build.WriteString("= @")
			build.WriteString(key)
			build.WriteString(" and ")
			build.WriteString(refer.KeyField)
			build.WriteString(" != @")
			build.WriteString(refer.KeyJson)

			where[key] = data[key] // reflectutil.GetFieldValue(refer, "G"+key)
		}

		build.WriteString(") TMP")

		txt := strings.Replace(build.String(), " union all ", " ", 1)
		txt = strings.Replace(txt, "${DbTableName}", gorm.GetDbName(refer.JsonDbName)+refer.TableName, -1)
		txt = strings.Replace(txt, "${TableName}", refer.TableName, -1)

		iCount := 0
		dbResult := gorm.Raw(txt, where).Find(&iCount)
		if dbResult.Error != nil {
			Log.Error("验证数据是否重复发生异常:", dbResult.Error)
			return msgentity.Err(1003, "验证数据是否重复发生异常:", dbResult.Error)
		}

		if iCount != 0 {
			var temp strings.Builder
			str := fmt.Sprintf("%0*d", len(checkRepeatAlone), iCount)
			array := []rune(str) //得到字符数组

			ml := len(checkRepeatAlone)
			for key, value := range checkRepeatAlone {
				i := len(strconv.Itoa(value))
				if array[ml-i] == 48 { // ASCII对应: '0' => 48, '1' => 49
					continue
				}

				fieldInfo := refer.GetField(key)
				temp.WriteString("、'")
				temp.WriteString(fieldInfo.Comment)
				temp.WriteString("'")
			}

			temp.WriteString("存在重复")

			return msgentity.Err(1004, strings.Replace(temp.String(), "、", "", 1))
		}

		k++
	}

	if k == 0 {
		return msgentity.Success("没有设定验证函数,通过")
	}

	return msgentity.Success("经验证,通过")
}

/**
 * 读取树形结构数据
 * @param ctx GinHttp上下文对象
 * @param refer
 * @param groupColumn
 * @param groupName
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindByTree(ctx ginutil.Context, refer *dbinfo.VirtualEntity, groupColumn, groupName string) *msgentity.MsgEntity {
	if !refer.HasPid {
		return msgentity.Err(1001, "指定分组字段不存在！")
	}

	//-- 从文件读取 --//
	var filePath string

	if groupName == "" {
		filePath = "./temp/cache/" + refer.TableName + "/tree.txt"
	} else {
		filePath = "./temp/cache/" + refer.TableName + "/Group_" + groupName + ".txt"
	}

	bl, _, data := jsonutil.FormFile(filePath, map[string]interface{}{})
	if bl {
		return msgentity.Success(data, "在文件中找到") //返回结果
	}

	//-- 从数据库读取 --//
	var build strings.Builder
	build.WriteString("SELECT ")

	mainTableName := refer.TableName
	fieldInfoList := refer.Fields
	for _, fieldInfo := range fieldInfoList {
		build.WriteString(mainTableName)
		build.WriteString(".")
		build.WriteString(fieldInfo.Field)
		build.WriteString(" AS ")
		build.WriteString(fieldInfo.JsonName)
		build.WriteString(",")
	}

	build.WriteString(" FROM ${DbTableName} AS ")
	build.WriteString(mainTableName)

	build.WriteString(" WHERE ")
	build.WriteString(dbinfo.TableMajorKeyString[0])
	build.WriteString(" > 0")

	where := []interface{}{}
	if groupName != "" {
		build.WriteString(" AND ")
		build.WriteString(dbinfo.TablePathKey[0])
		build.WriteString(" LIKE (")
		build.WriteString(" 	select CONCAT(a.")
		build.WriteString(dbinfo.TablePathKey[0])
		build.WriteString(", '%')")
		build.WriteString(" 	from ${DbTableName} a")

		if groupColumn != "" {
			field := refer.GetFieldName(groupColumn)
			build.WriteString(" 	where a.")
			build.WriteString(field) //指定字段作为分组标识
			build.WriteString(" = ?")
		} else if refer.HasOnlyign { //启用唯一标识作为关键字
			build.WriteString(" 	where a.")
			build.WriteString(dbinfo.TableOnlyign[0]) //启用唯一标识作为关键字
			build.WriteString(" = ?")                 //启用唯一标识作为关键字
		} else {
			build.WriteString(" 	where a.")
			build.WriteString(dbinfo.TableTreeNode[0])
			build.WriteString(" = ?")
		}

		build.WriteString(" )")
		where = append(where, groupName)
	}

	build.WriteString(" ORDER BY ")
	build.WriteString(dbinfo.TablePathKey[0])

	txt := strings.Replace(build.String(), "${DbTableName}", gorm.GetDbName(refer.JsonDbName)+refer.TableName, -1)
	txt = strings.Replace(txt, "${TableName}", refer.TableName, -1)
	txt = strings.Replace(txt, ", FROM ", " FROM ", -1)

	rows, err := gorm.Raw(txt, where).Rows()
	if err != nil {
		Log.Error("查询发生异常:", err)
		return msgentity.Err(1002, "查询发生异常:", err)
	}
	defer rows.Close()

	res := gorm.ScanRows2mapI(rows)
	if res == nil {
		return msgentity.Err(1003, "查询后数据转换发生异常")
	}

	if len(res) < 1 {
		return msgentity.Err(1004, "数据为空")
	}

	rootValue := dbinfo.TableTreeRootValue[0]
	if groupName != "" {
		rootValue = res[0][dbinfo.TableMajorKeyString[0]].(string) //分组查询情况下必须要一个根节点(因为已经path排序)
	}

	me := service.CreateTree(res, rootValue, dbinfo.TableMajorKeyString[0], dbinfo.TablePidKey[0], "childs")
	if !me.Success {
		return me
	}

	if len((me.Data).([]interface{})) < 1 {
		return msgentity.Err(1005, "数据转换后构造树型数据为空")
	}

	jsonutil.ToFile(me.Data, filePath) //保存到文件

	return msgentity.Success(me.Data, "查询成功")
}

/**
 * List转树形结构
 * @param source Map或切片结构
 * @param rootName
 * @param idFieldName
 * @param pIdFieldName
 * @param childFieldName
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) CreateTree(source interface{},
	rootName, idFieldName, pIdFieldName, childFieldName string) *msgentity.MsgEntity {
	if source == nil {
		return msgentity.Err(5001, "没有数据无法进行树结构创建!")
	}

	if strings.TrimSpace(idFieldName) == "" {
		return msgentity.Err(5002, "对象字段中的编号属性名称必须提供!")
	}

	if strings.TrimSpace(pIdFieldName) == "" {
		return msgentity.Err(5003, "对象字段中的上级编号属性名称必须提供!")
	}

	if strings.TrimSpace(childFieldName) == "" {
		return msgentity.Err(5004, "对象字段中的子节点集合属性名称必须提供!")
	}

	sourceTypeName := reflect.TypeOf(source).String()
	if strings.HasPrefix(sourceTypeName, "[]map[string]interface") {
		return service.createTreeByMap(source.([]map[string]interface{}), rootName, idFieldName, pIdFieldName, childFieldName)
	}

	return service.createTreeByList(source.([]interface{}), rootName, idFieldName, pIdFieldName, childFieldName)
}

/**
 * List转树形结构
 * @param source 切片结构
 * @param rootName
 * @param idFieldName
 * @param pIdFieldName
 * @param childFieldName
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) createTreeByList(source []interface{},
	rootName, idFieldName, pIdFieldName, childFieldName string) *msgentity.MsgEntity {
	if source == nil || (len(source) < 1) {
		return msgentity.Err(5001, "没有数据无法进行树结构创建!")
	}

	result := []interface{}{}

	rt := reflect.TypeOf(source[0])
	sourceTypeName := rt.String()

	isMap := strings.HasPrefix(sourceTypeName, "map[string]interface") //如果数据类型是Map则取值不能用反射方式

	if strings.TrimSpace(rootName) == "" {
		rootName = dbinfo.TableTreeRootValue[0] //未指定就默认为'00'做根节点
	}

	//-- 将所有数据进行预分组存储,同时筛选出根节点 --//
	groupMap := map[string][]interface{}{} //待进行挂接的子分组
	allMap := map[string]interface{}{}
	for _, object := range source {
		groupName := ""
		if !isMap {
			groupName = reflectutil.GetFieldValue(object, pIdFieldName).(string)
		} else {
			groupName = (object.(map[string]interface{}))[pIdFieldName].(string)
		}

		if strings.TrimSpace(groupName) == "" {
			groupName = rootName //如果父节点信息为空,则默认为根节点
		}

		groupName = strings.TrimSpace(groupName) //所在组名

		sid := ""
		if isMap {
			sid = (object.(map[string]interface{}))[idFieldName].(string)
		} else {
			sid = (reflectutil.GetFieldValue(object, idFieldName)).(string)
		}

		allMap[sid] = object

		if rootName == groupName {
			result = append(result, object) //加入根节点列表
			continue
		}

		childs, ok := groupMap[groupName]
		if !ok {
			childs = []interface{}{}
			groupMap[groupName] = childs
		}

		childs = append(childs, object)
		groupMap[groupName] = childs
	}

	//--将所有分组寻找父节点--//
	for key, value := range groupMap {
		obj := allMap[key]
		if obj == nil {
			continue
		}

		typeName := reflect.TypeOf(obj).String()
		if strings.HasPrefix(typeName, "map[string]interface") {
			(obj.(map[string]interface{}))[childFieldName] = value
			continue
		}

		reflectutil.SetFieldValue(obj, childFieldName, value) // 设置子节点集合
	}

	return msgentity.Success(result, "构造成功!")
}

/**
 * List转树形结构
 * @param source Map结构
 * @param rootName
 * @param idFieldName
 * @param pIdFieldName
 * @param childFieldName
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) createTreeByMap(source []map[string]interface{},
	rootName, idFieldName, pIdFieldName, childFieldName string) *msgentity.MsgEntity {
	if source == nil || (len(source) < 1) {
		return msgentity.Err(5001, "没有数据无法进行树结构创建!")
	}

	result := []interface{}{}

	rt := reflect.TypeOf(source[0])
	sourceTypeName := rt.String()

	isMap := strings.HasPrefix(sourceTypeName, "map[string]interface") //如果数据类型是Map则取值不能用反射方式

	if strings.TrimSpace(rootName) == "" {
		rootName = dbinfo.TableTreeRootValue[0] //未指定就默认为'00'做根节点
	}

	//-- 将所有数据进行预分组存储,同时筛选出根节点 --//
	groupMap := map[string][]interface{}{} //待进行挂接的子分组
	allMap := map[string]interface{}{}
	for _, object := range source {
		groupName := ""
		if !isMap {
			groupName = reflectutil.GetFieldValue(object, pIdFieldName).(string)
		} else {
			groupName = object[pIdFieldName].(string)
		}

		if strings.TrimSpace(groupName) == "" {
			groupName = rootName //如果父节点信息为空,则默认为根节点
		}

		groupName = strings.TrimSpace(groupName) //所在组名

		sid := ""
		if isMap {
			sid = object[idFieldName].(string)
		} else {
			sid = (reflectutil.GetFieldValue(object, idFieldName)).(string)
		}

		allMap[sid] = object

		if rootName == groupName {
			result = append(result, object) //加入根节点列表
			continue
		}

		childs, ok := groupMap[groupName]
		if !ok {
			childs = []interface{}{}
			groupMap[groupName] = childs
		}

		childs = append(childs, object)
		groupMap[groupName] = childs
	}

	//--将所有分组寻找父节点--//
	for key, value := range groupMap {
		obj := allMap[key]
		if obj == nil {
			continue
		}

		typeName := reflect.TypeOf(obj).String()
		if strings.HasPrefix(typeName, "map[string]interface") {
			(obj.(map[string]interface{}))[childFieldName] = value
			continue
		}

		reflectutil.SetFieldValue(obj, childFieldName, value) // 设置子节点集合
	}

	return msgentity.Success(result, "构造成功!")
}

/**
 * 根据字段名取指定记录编号的数据库表中对应字段的值
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param id
 * @param fieldNames 待取数据的字段名称集合
 * @return *msgentity.MsgEntity 返回验证结果 返回内容data中存放的是Map
 */
func (service VirtualService) GetValueByFieldNameVirtual(ctx ginutil.Context, refer *dbinfo.VirtualEntity, params map[string]interface{}) *msgentity.MsgEntity {
	if len(params) < 1 {
		return msgentity.Err(9101, "请求参数缺失")
	}

	id := params[refer.KeyJson]
	var fieldNames []string
	if v, ok := params["fieldNames"]; ok {
		fieldNames = v.([]string)
	}
	return service.GetValueByFieldName(ctx, service.VirtualEntity, id, fieldNames)
}

/**
 * 根据字段名取指定记录编号的数据库表中对应字段的值
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param id
 * @param fieldNames 待取数据的字段名称集合
 * @return *msgentity.MsgEntity 返回验证结果 返回内容data中存放的是Map
 */
func (service VirtualService) GetValueByFieldName(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, fieldNames []string) *msgentity.MsgEntity {
	currentUser := ""
	onlyCreator := !EnableTag(refer, 5)
	if onlyCreator { //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
		currentUser = CurrentLoginUserId(ctx.Request)
	}

	return commonDao.GetValueByFieldName(refer, id, fieldNames, currentUser, onlyCreator)
}

/**
 * 根据字段名取指定记录编号的数据库表中对应字段的值
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param id
 * @param fieldName 待取数据的字段名称集合
 * @return *msgentity.MsgEntity 返回验证结果 返回内容data中存放的是Map
 */
func (service VirtualService) GetValueByField(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}, fieldName string) *msgentity.MsgEntity {
	currentUser := ""
	onlyCreator := !EnableTag(refer, 5)
	if onlyCreator { //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
		currentUser = CurrentLoginUserId(ctx.Request)
	}

	return commonDao.GetValueByField(refer, id, fieldName, currentUser, onlyCreator)
}

/**
 * 根据字段名取指定记录编号的数据库表中对应字段的值
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param whereInfo 条件
 * @param fieldName 待取数据的字段名称集合
 * @return *msgentity.MsgEntity 返回验证结果 返回内容data中存放的是Map
 */
func (service VirtualService) GetValueByWhere(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo, fieldName string) *msgentity.MsgEntity {
	currentUser := ""
	onlyCreator := !EnableTag(refer, 5)
	if onlyCreator { //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
		currentUser = CurrentLoginUserId(ctx.Request)
	}

	return commonDao.GetValueByWhere(refer, whereInfo, fieldName, currentUser, onlyCreator)
}

/**
 * 取记录对应的版本号
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param idName 编号
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) GetEdition(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}) *msgentity.MsgEntity {
	if fmt.Sprintf("%v", id) == "" {
		return msgentity.Err(8001, "记录编号参数为空！")
	}

	return commonDao.GetEdition(refer, id)
}

/**
 * 取记录对应的状态值
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param idName 编号
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) GetState(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}) *msgentity.MsgEntity {
	if fmt.Sprintf("%v", id) == "" {
		return msgentity.Err(8001, "记录编号参数为空！")
	}

	return commonDao.GetState(refer, id)
}

/**
 * 根据关键值取对象集合
 * @param ctx GinHttp上下文对象
 * @Param refer 实体类
 * @Param where 存放查询条件
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindByKey(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo) *msgentity.MsgEntity {
	whereInfo = service.holdByEntityToWhereInfo(refer, whereInfo) //按实体保留条件
	if len(whereInfo) < 1 {
		return msgentity.Err(8001, "没有对应的查询条件！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindByKey(refer, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 根据关键值取对象集合中的第一个
 * @param ctx GinHttp上下文对象
 * @Param refer 实体类
 * @Param where 存放查询条件
 * @param fields 指定要查询的字段集合
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindOneByKey(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo, fields ...string) *msgentity.MsgEntity {
	whereInfo = service.holdByEntityToWhereInfo(refer, whereInfo) //按实体保留条件
	if len(whereInfo) < 1 {
		return msgentity.Err(8001, "没有对应的查询条件！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindOneByKey(refer, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator, fields...)
}

/**
 * 根据关键值取对象集合中的符合条件的第一条记录的指定字段
 * @param ctx GinHttp上下文对象
 * @Param refer 实体类
 * @Param where 存放查询条件
 * @param fieldName 指定要查询的字段
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindValueByKey(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo, fieldName string) *msgentity.MsgEntity {
	whereInfo = service.holdByEntityToWhereInfo(refer, whereInfo) //按实体保留条件
	if len(whereInfo) < 1 {
		return msgentity.Err(8001, "没有对应的查询条件！")
	}

	fieldName = strings.TrimSpace(fieldName)
	if fieldName == "" {
		return msgentity.Err(8002, "没有待查字段！")
	}

	if _, ok := refer.Fields[fieldName]; !ok {
		return msgentity.Err(8003, "指定字段不存在！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindValueByKey(refer, whereInfo, fieldName, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 根据指定字段进行分组查询
 * @param ctx GinHttp上下文对象
 * @Param refer 实体类
 * @Param where 存放查询条件
 * @param fieldMap 指定要查询的字段集合(原字段, 别名)
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindByFields(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo, fieldMap map[string]string) *msgentity.MsgEntity {
	whereInfo = service.holdByEntityToWhereInfo(refer, whereInfo) //按实体保留条件
	if len(whereInfo) < 1 {
		return msgentity.Err(8001, "没有对应的查询条件！")
	}

	if len(fieldMap) < 1 {
		return msgentity.Err(8002, "没有待查字段！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindByFields(refer, whereInfo, fieldMap, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 根据关键值查数量
 * @param ctx GinHttp上下文对象
 * @Param refer 实体类
 * @Param where 存放查询条件
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindCountByKey(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo) *msgentity.MsgEntity {
	whereInfo = service.holdByEntityToWhereInfo(refer, whereInfo) //按实体保留条件
	if len(whereInfo) < 1 {
		return msgentity.Err(7001, "没有对应的查询条件！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.FindCountByKey(refer, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator)
}

// /**
//  * 以事务方式执行Mapper下的多个方法
//  * 注意:Mapper必须存在才能执行
//  * @param mapper iBatis实体
//  * @Param funcInfo 接口信息集合(以3对为一组) <函数名, 函数参数类型集合, 函数参数集合, 函数名, 函数参数类型集合, 函数参数集合....>
//  * @return *msgentity.MsgEntity 返回验证结果 返回对象数组(各函数执行结果)
//  */
// func (service VirtualService) transactionMapping(Object mapper, Object...funcInfo) *msgentity.MsgEntity {

// 	return msgentity.Success(res, "查询成功")
// }

/**
 * 根据字段名取分组数据
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param Creator 指定用户
 * @param fields 字段名与别名对象
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) GroupByField(ctx ginutil.Context, refer *dbinfo.VirtualEntity, Creator string, fields map[string]string) *msgentity.MsgEntity {
	if len(fields) < 1 {
		return msgentity.Err(8001, "没有对应的待查字段！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.GroupByField(refer, Creator, fields, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 根据字段名取分组数据及分组后数量
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param Creator 指定用户
 * @param fields 字段名与别名对象
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) GroupByFieldAndCount(ctx ginutil.Context, refer *dbinfo.VirtualEntity, Creator string, fields map[string]string) *msgentity.MsgEntity {
	if len(fields) < 1 {
		return msgentity.Err(8001, "没有对应的待查字段！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.GroupByFieldAndCount(refer, Creator, fields, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 取表中指定字段的最大值
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param Creator 指定用户
 * @param field 字段名
 * @param where 查询条件字符串
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) MaxByField(ctx ginutil.Context, refer *dbinfo.VirtualEntity, Creator string, field string, whereInfo []dbinfo.WhereInfo) *msgentity.MsgEntity {
	field = strings.TrimSpace(field)
	if field == "" {
		return msgentity.Err(7001, "没有待查字段！")
	}

	if len(whereInfo) < 1 {
		return msgentity.Err(7002, "没有对应的查询条件！")
	}

	if _, ok := refer.Fields[field]; !ok {
		return msgentity.Err(7003, "指定字段不存在！")
	}

	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.MaxByField(refer, Creator, field, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 取表中指定字段的最小值
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param Creator 指定用户
 * @param field 字段名
 * @param where 查询条件
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) MinByField(ctx ginutil.Context, refer *dbinfo.VirtualEntity, Creator string, field string, whereInfo []dbinfo.WhereInfo) *msgentity.MsgEntity {
	field = strings.TrimSpace(field)
	if field == "" {
		return msgentity.Err(7001, "没有待查字段！")
	}

	if len(whereInfo) < 1 {
		return msgentity.Err(7002, "没有对应的查询条件！")
	}

	if _, ok := refer.Fields[field]; !ok {
		return msgentity.Err(7003, "指定字段不存在！")
	}

	onlyCreator := EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.MinByField(refer, Creator, field, whereInfo, CurrentLoginUserId(ctx.Request), onlyCreator)
}

/**
 * 检查关键值记录是否存在(返回1:存在;0:不存在)
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @Param id
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) HasById(ctx ginutil.Context, refer *dbinfo.VirtualEntity, id interface{}) *msgentity.MsgEntity {
	if fmt.Sprintf("%v", id) == "" {
		return msgentity.Err(8001, "记录编号参数为空！")
	}

	return commonDao.HasById(refer, id)
}

/**
 * 检查关键值记录是否存在(返回1:存在;0:不存在)
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @Param keyName 字段名
 * @Param keyValue 字段值
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) HasByKey(ctx ginutil.Context, refer *dbinfo.VirtualEntity, keyName string, keyValue interface{}) *msgentity.MsgEntity {
	keyName = strings.TrimSpace(keyName)
	if keyName == "" {
		return msgentity.Err(7001, "字段名参数为空！")
	}

	if (keyValue == nil) || (fmt.Sprintf("%v", keyValue) == "") || (fmt.Sprintf("%v", keyValue) == "<nil>") {
		return msgentity.Err(7002, "字段值参数为空！")
	}

	if _, ok := refer.Fields[keyName]; !ok {
		return msgentity.Err(7003, "指定字段不存在！")
	}

	fieldInfo := refer.GetField(keyName)
	if fieldInfo == nil {
		return msgentity.Err(7004, "字段备注信息缺失")
	}

	switch fieldInfo.DbFileType {
	case "int":
		temp, err := strconv.Atoi(keyValue.(string))
		if err != nil {
			return msgentity.Err(7005, "字段值参数为不符合规范！")
		}
		keyValue = temp
	case "bigint":
		temp, err := strconv.ParseInt(keyValue.(string), 10, 64)
		if err != nil {
			return msgentity.Err(7006, "字段值参数为不符合规范！")
		}
		keyValue = temp
	}

	return commonDao.HasByKey(refer, keyName, keyValue)
}

/**
 * 清理指定用户的缓存
 * @param ctx GinHttp上下文对象
 * @param cacheName 缓存名
 * @Param user 用户名
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) ClearCache(ctx ginutil.Context, cacheName, user string) *msgentity.MsgEntity {
	cacheName = strings.TrimSpace(cacheName)
	if cacheName == "" {
		return msgentity.Err(7001, "指定'缓存库名称'参数为空！")
	}

	val, bl := ctx.Get("Controller")
	if val == nil || !bl {
		return msgentity.Success(7002, "没有控制器对象！")
	}

	user = strings.TrimSpace(user)
	if user != "" {
		user = user + "_"
	}

	filePath := AppPath() + "/temp/cache/" + service.JsonDbName + "/" + service.JsonName + "/" + user + cacheName

	bl, _ = fileutil.Del(filePath) //删除文件
	if !bl {
		return msgentity.Err(7004, "清理失败！")
	}

	Log.Info("清理缓存库:" + cacheName)

	return msgentity.Err(7002, "清理失败！")
}

/**
 * Aop方式清理缓存
 * @param ctx GinHttp上下文对象
 * @param params 请求参数串
 * @return
 */
func (service VirtualService) AopClearCache(ctx ginutil.Context, params ...interface{}) *msgentity.MsgEntity {
	val, bl := ctx.Get("Controller")
	if val == nil || !bl {
		return msgentity.Success(1001, "没有控制器对象！")
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + service.JsonDbName + "/" + service.JsonName + "/"
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return msgentity.Success(1999, "Aop请求结束")
}

/**
 * 查询组结构数据
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param groupColumn 分组名(树节点)所在字段名
 * @param groupName 分组名(树节点)
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) FindByGroup(ctx ginutil.Context, refer *dbinfo.VirtualEntity, groupColumn, groupName string) *msgentity.MsgEntity {
	return service.FindByTree(ctx, refer, groupColumn, groupName)
}

/**
 * 添加数据到指定组下
 * 警告:对象必须符合树形结构要求,如:Id、Pid
 * @param ctx GinHttp上下文对象
 * @param refer 实体对象
 * @param groupName 分组字段名称(树节点)
 * @param groupValue 分组字段值(树节点)
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) AddToGroup(ctx ginutil.Context, refer *dbinfo.VirtualEntity, groupName, groupValue string) *msgentity.MsgEntity {
	if groupName == "" {
		return msgentity.Err(8001, "节点参数不能为空!")
	}

	if refer == nil {
		return msgentity.Err(8002, "实体对象不能为空!")
	}

	if !refer.HasPid {
		return msgentity.Err(8003, "指定分组字段不存在！")
	}

	if dbinfo.TableMajorKeyString[0] != refer.KeyField {
		return msgentity.Err(8004, "实体类型没有Id字段,不符合格式要求!")
	}

	if !refer.HasPid {
		return msgentity.Err(8005, "实体类型没有Pid字段,不符合格式要求!")
	}

	//-- 查组所在记录编号 --//
	var build strings.Builder
	build.WriteString("SELECT ")
	build.WriteString(dbinfo.TableMajorKeyString[0])
	build.WriteString(" FROM ")
	build.WriteString(refer.TableName)
	build.WriteString(" WHERE ")
	build.WriteString(groupName)
	build.WriteString("=? LIMIT 0, 1")

	pid := ""
	dbResult := gorm.Raw(build.String(), groupValue).Find(&pid)
	if dbResult.Error != nil {
		Log.Error("查询发生异常:", dbResult.Error)
		return msgentity.Err(8006, "查询发生异常:", dbResult.Error)
	}

	if pid == "" {
		return msgentity.Err(8007, "指定组不存在,不能用此方法添加!")
	}

	reflectutil.SetFieldValue(refer, dbinfo.TablePidKey[1], pid) // 父编号就是查出来的数据

	refer.SetDefault(false) //对对象中添加了fieldInfo注解的属性添加默认值

	me := service.SupplyDbEntityAttrByAdd(ctx, refer, "", "")
	if !me.Success {
		return me.IncCode(7030)
	}

	iCode, err := refer.ValidAttrByAdd() //对对象中添加了dbinfo.DataInfo注解的属性检查限制
	if err != nil {
		return msgentity.Err(iCode+7020, err.Error())
	}

	me = service.ValidEntityRepeatByAdd(ctx, refer) //验证新增数据是否存在重复
	if !me.Success {
		return me.IncCode(7030)
	}

	return commonDao.AddCommon(refer)
}

/**
 * 执行SQL脚本获取单行单列数据
 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
 * @param sql 待执行的SQL脚本
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) DoSql(sql string) *msgentity.MsgEntity {
	return commonDao.DoSql(sql)
}

/**
 * 执行SQL脚本获取单行单列数据
 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
 * @param sql 待执行的SQL脚本
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) ExecSql(sql string) *msgentity.MsgEntity {
	return commonDao.ExecSql(sql)
}

/**
 * 执行SQL脚本获取单行单列数据
 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
 * @param sql 待执行的SQL脚本
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) GetValue(sql string) *msgentity.MsgEntity {
	return commonDao.GetValue(sql)
}

/**
 * 执行SQL脚本获取一行数据(多列)
 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录
 * @param sql 待执行的SQL脚本
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) GetRow(sql string) *msgentity.MsgEntity {
	return commonDao.GetRow(sql)
}

/**
 * 执行SQL脚本获取多行数据(多列)
 * 注意:库名必须用${}进行包装,此脚本可返回多条记录
 * @param sql SQL脚本
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) GetRows(sql string) *msgentity.MsgEntity {
	return commonDao.GetRows(sql)
}

/**
 * 根据关键值翻转值(限布尔值类型,1转2,2转1)
 * 警告:此方法只支持布尔值类型,且只支持翻转1和2
 * @param ctx GinHttp上下文对象
 * @Param refer 实体类
 * @Param whereInfo 存放查询条件
 * @Param reversalColumn 翻转的字段名
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) ReversalByKey(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo, reversalColumn string) *msgentity.MsgEntity {
	currentUser := CurrentLoginUserId(ctx.Request)
	onlyCreator := !EnableTag(refer, 6) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除

	return commonDao.ReversalByKey(refer, whereInfo, reversalColumn, currentUser, onlyCreator)
}

/**
 * 根据条件仅查询指定字段名数据
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param whereInfo
 * @param fieldNames 待取数据的字段名称集合
 * @return *msgentity.MsgEntity 返回验证结果 返回内容data中存放的是Map
 */
func (service VirtualService) FindField(ctx ginutil.Context, refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo, fieldNames []string) *msgentity.MsgEntity {
	currentUser := ""
	onlyCreator := !EnableTag(refer, 5) //7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
	if onlyCreator {
		currentUser = CurrentLoginUserId(ctx.Request)
	}

	return commonDao.FindField(refer, whereInfo, fieldNames, currentUser, onlyCreator)
}

/**
 * 上传文件
 * @param ctx GinHttp上下文对象
 * @param modelName 模块名称
 * @return *msgentity.MsgEntity 返回验证结果
 */
func (service VirtualService) UpFile(ctx ginutil.Context, modelName string) *msgentity.MsgEntity {
	if upFilePath == "" {
		upFilePath = ReadConfigKey("App", "UpFilePath", "./data/app/").(string)
		if !strings.HasSuffix(upFilePath, "/") {
			upFilePath = upFilePath + "/"
		}
	}

	// 指定上传目录
	targetDir := upFilePath + modelName
	// 确保目录存在
	if err := os.MkdirAll(targetDir, 0755); err != nil {
		return msgentity.Err(8001, "无法创建目录！")
	}

	// 单个文件上传示例
	file, err := ctx.FormFile("file")
	if err != nil {
		return msgentity.Err(8002, "'file'参数缺失！")
	}

	// 读取文件
	src, err := file.Open()
	if err != nil {
		return msgentity.Err(8003, "无法打开上传的文件！")
	}

	defer src.Close()

	sFilename := uuidutil.Get()
	// 保存文件到指定目录
	dst, err := os.Create(filepath.Join(targetDir, sFilename))
	if err != nil {
		return msgentity.Err(8004, "无法保存文件！")
	}
	defer dst.Close()

	_, err = dst.ReadFrom(src)
	if err != nil {
		return msgentity.Err(8005, "保存文件内容失败！")
	}

	return msgentity.Success(sFilename, "上传成功！")
}

/**
 * 获取图片
 * @param ctx GinHttp上下文对象
 * @param modelName 模块名称
 * @param filename 文件名
 */
func (service VirtualService) LookImg(ctx ginutil.Context, modelName, filename string) {
	if (filename == "") || (filename == "null") {
		modelName = "imgs"
		filename = "空图片.png"
	}

	if upFilePath == "" {
		upFilePath = ReadConfigKey("App", "UpFilePath", "./data/app/").(string)
		if !strings.HasSuffix(upFilePath, "/") {
			upFilePath = upFilePath + "/"
		}
	}

	filePath := upFilePath + modelName + "/" + filename // 假设文件存储在 ./texts 目录下

	// 读取图片文件
	content, err := os.ReadFile(filePath)
	if err != nil {
		ctx.AbortWithStatus(http.StatusInternalServerError)
		return
	}

	// 获取文件的MIME类型
	mimeType := http.DetectContentType(content[:512])

	// 使用 c.Data() 发送图片二进制数据
	ctx.Data(http.StatusOK, mimeType, content)
}

/**
 * 按实体保留切片中的数据
 * object 待检查对象
 * whereInfo 数据
 * @return []dbinfo.WhereInfo 返回保留后的切片数据
 */
func (VirtualService) holdByEntityToWhereInfo(refer *dbinfo.VirtualEntity, whereInfo []dbinfo.WhereInfo) []dbinfo.WhereInfo {
	result := []dbinfo.WhereInfo{}
	for _, val := range whereInfo {
		if _, ok := refer.Fields[val.Name]; !ok {
			continue
		}

		result = append(result, val)
	}

	return result
}

// 新增时需要排除的字段(不允许前端传入)
func addRemoveNameArray() []string {
	addRemoveOnce.Do(func() {
		addRemoveNames = []string{
			dbinfo.TableMajorKeyString[1],  //["sId"]           数据库表主键名称(字符串形式)
			dbinfo.TableMajorKeyAutoInt[1], //["iId"]           数据库表主键名称(自增长形式)
			dbinfo.TableMajorKeyUuId[1],    //["uId"]           数据库表主键名称(UUID形式)
			dbinfo.TableCreator[1],         //["sCreator"]      数据库表字段名称-创建人
			dbinfo.TableCreateDate[1],      //["dCreateDate"]   数据库表字段名称-创建时间
			dbinfo.TableModifieder[1],      //["sModifieder"]   数据库表字段名称-修改人
			dbinfo.TableModifiedDate[1],    //["dModifiedDate"] 数据库表字段名称-修改时间
			dbinfo.TableState[1],           //["iState"]        数据库表字段名称-状态值
			dbinfo.TableRrank[1],           //["iRank"]         数据库表字段名称-排序值
			dbinfo.TableEdition[1],         //["iEdition"]      数据库表字段名称-版本号
			dbinfo.TableDelSign[1],         //["iDelSign"]      数据库表字段名称-逻辑删除标识
		}
	})

	return addRemoveNames
}

// 取新增时检验的忽略字段
func addValidIgnoreNameArray() []string {
	addValidOnce.Do(func() {
		addValidIgnoreNames = []string{
			dbinfo.TableMajorKeyString[1],  //["sId"]           数据库表主键名称(字符串形式)
			dbinfo.TableMajorKeyAutoInt[1], //["iId"]           数据库表主键名称(自增长形式)
			dbinfo.TableMajorKeyUuId[1],    //["uId"]           数据库表主键名称(UUID形式)
			dbinfo.TablePathKey[1],         //["sPath"]         数据库表字段名称-主键路径名
			dbinfo.TableCreator[1],         //["sCreator"]      数据库表字段名称-创建人
			dbinfo.TableCreateDate[1],      //["dCreateDate"]   数据库表字段名称-创建时间
			dbinfo.TableModifieder[1],      //["sModifieder"]   数据库表字段名称-修改人
			dbinfo.TableModifiedDate[1],    //["dModifiedDate"] 数据库表字段名称-修改时间
			dbinfo.TableState[1],           //["iState"]        数据库表字段名称-状态值
			dbinfo.TableRrank[1],           //["iRank"]         数据库表字段名称-排序值
			dbinfo.TableEdition[1],         //["iEdition"]      数据库表字段名称-版本号
			dbinfo.TableDelSign[1],         //["iDelSign"]      数据库表字段名称-逻辑删除标识
			dbinfo.TableRecordKey[1],       //["sRecordKey"]    记录验证串字段名
		}
	})

	return addValidIgnoreNames
}

// 取修改时需要排除的字段(不允许前端传入)
func editRemoveNameArray() []string {
	editRemoveOnce.Do(func() {
		editRemoveNames = []string{
			dbinfo.TableCreator[1],      //["sCreator"]      数据库表字段名称-创建人
			dbinfo.TableCreateDate[1],   //["dCreateDate"]   数据库表字段名称-创建时间
			dbinfo.TableModifieder[1],   //["sModifieder"]   数据库表字段名称-修改人
			dbinfo.TableModifiedDate[1], //["dModifiedDate"] 数据库表字段名称-修改时间
			dbinfo.TableState[1],        //["iState"]        数据库表字段名称-状态值
			dbinfo.TableRrank[1],        //["iRank"]         数据库表字段名称-排序值
			dbinfo.TableDelSign[1],      //["iDelSign"]      数据库表字段名称-逻辑删除标识
			dbinfo.TableRecordKey[1],    //["sRecordKey"]    记录验证串字段名
		}
	})
	return editRemoveNames
}

// 取修改时检验的忽略字段
func editValidIgnoreNameArray() []string {
	editValidOnce.Do(func() {
		editValidIgnoreNames = []string{
			dbinfo.TablePathKey[1],      //["sPath"]         数据库表字段名称-主键路径名
			dbinfo.TableCreator[1],      //["sCreator"]      数据库表字段名称-创建人
			dbinfo.TableCreateDate[1],   //["dCreateDate"]   数据库表字段名称-创建时间
			dbinfo.TableModifieder[1],   //["sModifieder"]   数据库表字段名称-修改人
			dbinfo.TableModifiedDate[1], //["dModifiedDate"] 数据库表字段名称-修改时间
			dbinfo.TableState[1],        //["iState"]        数据库表字段名称-状态值
			dbinfo.TableRrank[1],        //["iRank"]         数据库表字段名称-排序值
			dbinfo.TableEdition[1],      //["iEdition"]      数据库表字段名称-版本号
			dbinfo.TableDelSign[1],      //["iDelSign"]      数据库表字段名称-逻辑删除标识
			dbinfo.TableRecordKey[1],    //["sRecordKey"]    记录验证串字段名
		}
	})

	return editValidIgnoreNames
}

// id转路径，并在每组之间插入 '/'
func idToPath(id string) string {
	var result strings.Builder
	length := len(id)

	result.WriteString("/")
	result.WriteString(dbinfo.TableTreeRootValue[0])
	result.WriteString("/")

	for i := 0; i < length; i += 2 {
		if i+2 <= length {
			result.WriteString(id[i : i+2])
		} else {
			result.WriteString(id[i:])
		}

		if i+2 < length {
			result.WriteString("/")
		}
	}

	result.WriteString("/")

	return result.String()
}

/**
 * 取控制开关
 * 控制开关,7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
 * 其中前5个为'是否仅创建者可操作'后续为其它控制开关
 * @param i 位数,从右到左数,下标从1开始
 * @return
 */
func EnableTag(refer *dbinfo.VirtualEntity, i int) bool {
	data := refer.EnableTag
	result := data / int(math.Pow10(i-1)) % 10

	return result != 1 //1代表限制,非1才是不限制
}

/**
 * 取查询控制开关(取控制开关简化方式)
 * @return
 */
func EnableFind(refer *dbinfo.VirtualEntity) bool {
	return EnableTag(refer, 5)
}

//-----------------------------------------------------------------//

func (service VirtualService) DoFund(ctx *gin.Context, fun string, params map[string]interface{}) (bool, interface{}) {
	if fun == "" {
		return false, msgentity.Err(9801, "方法名未明确")
	}

	switch strings.ToLower(fun) {
	case "/add": //新增
		return true, service.Add(ctx, service.VirtualEntity, params)
	case "/add/node": //新增树节点
		return true, service.AddNode(ctx, service.VirtualEntity, params)
	case "/adds": //批量新增
		return true, service.AddsVirtual(ctx, service.VirtualEntity, params)
	case "/change/state": //修改状态
		return true, service.ChangeStateVirtual(ctx, service.VirtualEntity, params)
	case "/change/setp": //修改步骤值(如果设置为单向则新值必须大于旧值)
		return true, service.ChangeSetpVirtual(ctx, service.VirtualEntity, params)
	case "/del": //删除
		return true, service.DelVirtual(ctx, service.VirtualEntity, params)
	case "/edit": //修改
		return true, service.Edit(ctx, service.VirtualEntity, params)
	case "/edits": //批量修改
		return true, service.EditsVirtual(ctx, service.VirtualEntity, params)
	case "/save": //保存(有ID则更新,否则新增)
		return true, service.Save(ctx, service.VirtualEntity, params)
	case "/saves": //批量保存
		return true, service.SavesVirtual(ctx, service.VirtualEntity, params)
	case "/find/id": //根据主键查询数据
		id := params[service.VirtualEntity.KeyJson]
		return true, service.FindById(ctx, service.VirtualEntity, id)
	case "/find/all": //查询所有数据
		return true, service.FindAllVirtual(ctx, service.VirtualEntity, params)
	case "/find/date": //查询指定时间内数据
		dateSt := stringutil.ToStr(params["dateSt"])
		dateEd := stringutil.ToStr(params["dateEd"])
		return true, service.FindByDate(ctx, service.VirtualEntity, dateSt, dateEd)
	case "/find/row": //查询指定行数据
		id := params[service.VirtualEntity.KeyJson]
		return true, service.FindByRow(ctx, service.VirtualEntity, id)
	case "/find/page": //查询分页数据
		var findByPageParam dbinfo.FindByPageParam
		if v, ok := params["findByPageParam"]; ok {
			findByPageParam = v.(dbinfo.FindByPageParam)
		}
		return true, service.FindByPage(ctx, service.VirtualEntity, findByPageParam)
	case "/find/tree": //读取树形结构数据
		groupName := stringutil.ToStr(params["groupName"])
		groupColumn := stringutil.ToStr(params["groupColumn"])
		return true, service.FindByTree(ctx, service.VirtualEntity, groupColumn, groupName)
	case "/get/field": //根据字段名取指定记录编号的数据库表中对应字段的值
		return true, service.GetValueByFieldNameVirtual(ctx, service.VirtualEntity, params)
	case "/get/field/id": //根据字段名取指定记录编号的数据库表中对应字段的值
		id := params[service.VirtualEntity.KeyJson]
		fieldName := stringutil.ToStr(params["fieldName"])
		return true, service.GetValueByField(ctx, service.VirtualEntity, id, fieldName)
	case "/get/where": //根据字段名取指定条件的数据库表中对应字段的值
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		fieldName := stringutil.ToStr(params["fieldName"])
		return true, service.GetValueByWhere(ctx, service.VirtualEntity, whereInfo, fieldName)
	case "/get/edition": //取记录对应的版本号
		id := params[service.VirtualEntity.KeyJson]
		return true, service.GetEdition(ctx, service.VirtualEntity, id)
	case "/get/state": //取记录对应的状态值
		id := params[service.VirtualEntity.KeyJson]
		return true, service.GetState(ctx, service.VirtualEntity, id)
	case "/find/key": //根据关键值取对象集合
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		return true, service.FindByKey(ctx, service.VirtualEntity, whereInfo)
	case "/find/key/one": //根据关键值取对象集合中的第一个
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		var fields []string
		if v, ok := params["fields"]; ok {
			fields = v.([]string)
		}
		return true, service.FindOneByKey(ctx, service.VirtualEntity, whereInfo, fields...)
	case "/find/key/value": //根据关键值取对象集合中的符合条件的第一条记录的指定字段
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		fieldName := stringutil.ToStr(params["fieldName"])
		return true, service.FindValueByKey(ctx, service.VirtualEntity, whereInfo, fieldName)
	case "/find/fields": //根据指定字段进行分组查询
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		var fieldMap map[string]string
		if v, ok := params["fieldMap"]; ok {
			fieldMap = v.(map[string]string)
		}
		return true, service.FindByFields(ctx, service.VirtualEntity, whereInfo, fieldMap)
	case "/find/key/count": //根据关键值查数量
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		return true, service.FindCountByKey(ctx, service.VirtualEntity, whereInfo)
	case "/group/field": //根据字段名取分组数据
		Creator := stringutil.ToStr(params["Creator"])
		var fields map[string]string
		if v, ok := params["fields"]; ok {
			fields = v.(map[string]string)
		}
		return true, service.GroupByField(ctx, service.VirtualEntity, Creator, fields)
	case "/group/field/count": //根据字段名取分组数据及分组后数量
		Creator := stringutil.ToStr(params["Creator"])
		var fields map[string]string
		if v, ok := params["fields"]; ok {
			fields = v.(map[string]string)
		}
		return true, service.GroupByFieldAndCount(ctx, service.VirtualEntity, Creator, fields)
	case "/max/field": //取表中指定字段的最大值
		Creator := stringutil.ToStr(params["Creator"])
		field := stringutil.ToStr(params["field"])
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		return true, service.MaxByField(ctx, service.VirtualEntity, Creator, field, whereInfo)
	case "/min/field": //取表中指定字段的最小值
		Creator := stringutil.ToStr(params["Creator"])
		field := stringutil.ToStr(params["field"])
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		return true, service.MinByField(ctx, service.VirtualEntity, Creator, field, whereInfo)
	case "/has/id": //检查关键值记录是否存在(返回1:存在;0:不存在)
		id := params[service.VirtualEntity.KeyJson]
		return true, service.HasById(ctx, service.VirtualEntity, id)
	case "/has/key": //检查关键值记录是否存在(返回1:存在;0:不存在)
		keyName := stringutil.ToStr(params["keyName"])
		keyValue := params["keyValue"]
		return true, service.HasByKey(ctx, service.VirtualEntity, keyName, keyValue)
	case "/clear/cache": //清理指定用户的缓存
		cacheName := stringutil.ToStr(params["cacheName"])
		user := stringutil.ToStr(params["user"])
		return true, service.ClearCache(ctx, cacheName, user)
	case "/find/group": //查询组结构数据
		groupColumn := stringutil.ToStr(params["groupColumn"])
		groupName := stringutil.ToStr(params["groupName"])
		return true, service.FindByGroup(ctx, service.VirtualEntity, groupColumn, groupName)
	case "/add/group": //添加数据到指定组下
		groupName := stringutil.ToStr(params["groupName"])
		groupValue := stringutil.ToStr(params["groupValue"])
		return true, service.AddToGroup(ctx, service.VirtualEntity, groupName, groupValue)
	case "/reversal/key": //根据关键值翻转值(限布尔值类型,1转2,2转1)
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		reversalColumn := stringutil.ToStr(params["reversalColumn"])
		return true, service.ReversalByKey(ctx, service.VirtualEntity, whereInfo, reversalColumn)
	case "/find/field": //根据条件仅查询指定字段名数据
		var whereInfo []dbinfo.WhereInfo
		if v, ok := params["whereInfo"]; ok {
			whereInfo = v.([]dbinfo.WhereInfo)
		}
		var fieldNames []string
		if v, ok := params["fieldNames"]; ok {
			fieldNames = v.([]string)
		}
		return true, service.FindField(ctx, service.VirtualEntity, whereInfo, fieldNames)
	case "/file/up": //上传文件
		modelName := stringutil.ToStr(params["modelName"])
		return true, service.UpFile(ctx, modelName)
	case "/file/img": //获取图片
		modelName := stringutil.ToStr(params["modelName"])
		filename := stringutil.ToStr(params["filename"])
		service.LookImg(ctx, modelName, filename)
		return true, nil
	}

	fun = fun[1:]
	if strings.Contains(fun, "/") || fun == "" {
		return false, msgentity.Err(9803, "指定方法不能在此使用:", fun)
	}

	return false, msgentity.Err(9805, "指定方法没有在对应的业务层实现:", fun)

	// String beanName = this.getDbObj() + "ServiceImpl";
	// String methodName = fun;

	// Object beanObj = SpringContextUtil.getBean(beanName);
	// if (null == beanObj) {
	// 	return MsgEntity.err(9804, "未找到指定方法,且没有对应的业务层:", beanName);
	// }

	// Object result = ModuleUtil.callServiceMethod(beanName, methodName, params);
	// if (result == null) {
	// 	return MsgEntity.err(9805, "指定方法没有在对应的业务层实现:", methodName);
	// }
}
